package com.moliku.insurance.process.service.impl;


import cn.hutool.core.util.CharsetUtil;
import com.alibaba.fastjson.JSONObject;
import com.moliku.insurance.common.constant.CompanyEnum;
import com.moliku.insurance.common.constant.InsureStatusEnum;
import com.moliku.insurance.common.constant.OrderEnum;
import com.moliku.insurance.common.constant.PolicyConfigKeyEnum;
import com.moliku.insurance.common.response.CommonInsureResult;
import com.moliku.insurance.common.util.ByteUtils;
import com.moliku.insurance.model.dto.CancelInsureDTO;
import com.moliku.insurance.model.dto.DownloadInsureDTO;
import com.moliku.insurance.model.dto.insure.InsureDTO;
import com.moliku.insurance.model.entity.HuaTai.*;
import com.moliku.insurance.model.entity.Order;
import com.moliku.insurance.model.entity.OrderDetail;
import com.moliku.insurance.process.mapper.BaseOrderMapper;
import com.moliku.insurance.process.service.ConfigService;
import com.moliku.insurance.process.strategy.PolicyStrategy;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 华泰保险
 *
 * @author Mr.Liu
 * @since 2021/2/25
 */
@Slf4j
@Service("HuaTaiService")
public class HuaTaiServiceImpl implements PolicyStrategy {

    private static final String URL_TB_HT="http://219.141.242.74:9039/service_platform/InsureInterface";
    private static final String URL_TUI_HT="http://219.141.242.74:9039/service_platform/SurrenderInterface";
    private static final String URL_DOWN_HT="http://219.141.242.74:9039/service_platform/PlyQueryInterface";

    private static final String KEY="123456@HT";
    private static final String CHANNEL_CODE="100026";

    @Resource
    private BaseOrderMapper baseOrderMapper;
    @Resource
    private ConfigService configService;



    @Override
    public CommonInsureResult submitPolicy(InsureDTO request) {
        String message="";
        try{
            JSONObject jsonObject;
            MultiValueMap<String,String> requestMessage = insuredEntities(request);
            String urlTb=configService.getConfigValue(CompanyEnum.HUATAI, PolicyConfigKeyEnum.SUBMIT_POLICY_URL);
            jsonObject = responseMessage(requestMessage,urlTb);
            message=jsonObject.getString("responseInfo");

            //修改订单详情表中投保时保险公司返回数据
            OrderDetail orderDetail=new OrderDetail();
            orderDetail.setOrderId(request.getLocalOrderId());
            orderDetail.setInsureRsp(jsonObject.toJSONString());
            baseOrderMapper.updateOrderDeatailByOrderId(orderDetail);

            //responseCode 0:失败 1:成功 2:订单号重复
            String responseCode="1".equals(jsonObject.getString("responseCode"))?"1":("2".equals(jsonObject.getString("responseCode"))?"2":"0");
            switch (responseCode){
                case "0":
                    log.error("华泰投保失败!{}", message);
                    return CommonInsureResult.submitPolicyFail(message);
                case "1":
                    log.info("投保成功!{}", jsonObject);
                    //更改订单状态
                    Order order = baseOrderMapper.selectById(request.getLocalOrderId());
                    order.setStatus(OrderEnum.CLOSED_NO_REFUND.getValue());
                    order.setPolicyNo(jsonObject.getString("policyNO"));
                    baseOrderMapper.updateById(order);
                    log.info("投保成功!");
                    return CommonInsureResult.submitPolicySuccess(jsonObject.getString("policyNO"));
                case "2":
                    log.error("华泰投保失败, 订单号重复!{}",InsureStatusEnum.INSURE_FAIL_5101);
                    return CommonInsureResult.submitPolicyFail(InsureStatusEnum.INSURE_FAIL_5101);
                default:
            }
        }catch (Exception e){
            log.error("华泰投保:",e);
        }
        return CommonInsureResult.submitPolicyFail(message);
    }

    @Override
    public CommonInsureResult cancelPolicy(CancelInsureDTO request) {
        String message="";
        try {
            String channelCode=configService.getConfigValue(CompanyEnum.HUATAI,"CHANNEL_CODE");
            Order order = baseOrderMapper.selectByPolicyNo(request.getPolicyNo());
            if (null==order){
                log.error("退保失败!{}",request.getPolicyNo());
                return CommonInsureResult.cancelPolicyFail();
            }
            Map<String,Object> map=new HashMap<>(6);
            map.put("bizCode","103");
            map.put("applyRefundTime",LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            map.put("channelCode",channelCode);
            map.put("channelName",request.getChannelName());
            map.put("orderId",request.getPolicyNo());
            map.put("policyNo",request.getPolicyNo());

            JSONObject jsonObject=new JSONObject(map);
            MultiValueMap<String,String> urlMap=new LinkedMultiValueMap<>(3);
            urlMap.add("signature",checkSignature(jsonObject.toJSONString()));
            urlMap.add("json",jsonObject.toJSONString());
            urlMap.add("channelCode",channelCode);

            String urlTui=configService.getConfigValue(CompanyEnum.HUATAI,PolicyConfigKeyEnum.CANCEL_POLICY_URL);
            jsonObject=responseMessage(urlMap,urlTui);

            message=jsonObject.getString("responseInfo");


            //修改订单详情表中退保时保险公司返回数据
            OrderDetail orderDetail=new OrderDetail();
            orderDetail.setOrderId(order.getId());
            orderDetail.setCancelPolicyRsp(jsonObject.toJSONString());
            baseOrderMapper.updateOrderDeatailByOrderId(orderDetail);


            //响应为1,为响应成功
            String responseCode="1".equals(jsonObject.getString("responseCode"))?"1":"0";
            switch (responseCode){
                case "1":
                    log.info("退保成功{}",request.getPolicyNo());
                    order.setPolicyNo(jsonObject.getString("policyNo"));
                    order.setStatus(OrderEnum.CANCEL.getValue());
                    baseOrderMapper.updateById(order);
                    return CommonInsureResult.cancelPolicySuccess();

                case "0":
                    log.error("退保失败!{}","保单号为:"+message);
                    return CommonInsureResult.cancelPolicyFail(message);
                default:
            }

        }catch (Exception e){
            log.error("华泰退保:",e);
        }

        return CommonInsureResult.cancelPolicyFail(message);
    }

    @Override
    public CommonInsureResult downloadPolicy(DownloadInsureDTO downloadInsure) {
        String message="";
        try {
            JSONObject jsonObject;
            String channelCode=configService.getConfigValue(CompanyEnum.HUATAI,"CHANNEL_CODE");
            Order order = baseOrderMapper.selectByPolicyNo(downloadInsure.getPolicyNo());
            HashMap<String,String> map=new HashMap<>(5);
            map.put("bizCode","107");
            map.put("applySearchTime",LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            map.put("channelCode",channelCode);
            map.put("channelName",order.getTripartiteCompanyName());
            map.put("orderId",order.getSerialNo());


            MultiValueMap<String,String> bodyMap=new LinkedMultiValueMap<>(3);
            bodyMap.add("signature",checkSignature(JSONObject.toJSONString(map)));
            bodyMap.add("channelCode",channelCode);
            bodyMap.add("json",JSONObject.toJSONString(map));
            String urlDown=configService.getConfigValue(CompanyEnum.HUATAI,PolicyConfigKeyEnum.DOWNLOAD_POLICY_URL);
            jsonObject=responseMessage(bodyMap,urlDown);
            message=jsonObject.getString("responseInfo");

            //如果响应码是1  查询保单后会返回下载电子保单接口
            String responseCode="1".equals(jsonObject.getString("responseCode"))?"1":"0";
            switch (responseCode){
                case "1":
                   String invoiceUrl= jsonObject.getString("policyUrl");
                    //返回电子保单信息
                    byte[] bytes = ByteUtils.urlToByte(invoiceUrl);
                    return CommonInsureResult.downloadPolicySuccess(bytes);
                case "0":
                    log.error("华泰未返回电子保单接口!{}",message);
                    return CommonInsureResult.downloadPolicyFail(message);
                default:
            }

        }catch (Exception e){
            log.error("华泰下载电子保单失败!{}",downloadInsure.getPolicyNo());
            e.printStackTrace();
        }

        return CommonInsureResult.downloadPolicyFail(message);
    }

    protected String checkSignature(String jsonString){
        String key=configService.getConfigValue(CompanyEnum.HUATAI,"KEY");
        String source =jsonString + key;
        String localMd5 = DigestUtils.md5Hex(source.getBytes(CharsetUtil.CHARSET_UTF_8));
        log.info("\n本地签名：" + localMd5);

        return localMd5;
    }


    /**
     * 投保
    */
    public MultiValueMap<String,String> insuredEntities(InsureDTO request){
        JSONObject jsonObject=new JSONObject();
        String channelCode=configService.getConfigValue(CompanyEnum.HUATAI,"CHANNEL_CODE");
       //添加渠道信息
        ChannelObject channelObject=new ChannelObject();
        channelObject.setBizCode("101");
        if (StringUtils.isNotEmpty(request.getOrder().getChannel2Name())){
            channelObject.setChannelName(request.getOrder().getChannel2Name());
        }else {
            channelObject.setChannelName(request.getOrder().getChannel1Name());
        }
        channelObject.setChannelCode(channelCode);

        channelObject.setOrderId(request.getOrder().getSerialNumber());
        channelObject.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        jsonObject.put("channelObject",channelObject);

        //添加险种信息
        InsuranceObject insuranceObject=new InsuranceObject();
        insuranceObject.setInsuranceCode("464103");
        insuranceObject.setInsuranceName(request.getOrder().getProductName());
        insuranceObject.setPlan("A");
        insuranceObject.setPrmCur("01");
        //必传 保费
        insuranceObject.setPremium(request.getOrder().getPremium());
        insuranceObject.setAmtCur("01");
        //必传 保额
        insuranceObject.setAmount(0);
        insuranceObject.setEffectiveTime(request.getOrder().getStartTime());
        insuranceObject.setTerminalTime(request.getOrder().getEndTime());
        insuranceObject.setCopy("1");
        jsonObject.put("insuranceObject",insuranceObject);

        //添加投保人信息
        AppntObject appntObject =new AppntObject();
        appntObject.setAppName(request.getPolicyHolder().getcName());
        appntObject.setAppType("1");
        appntObject.setAppIDType(getAppIdType(request.getPolicyHolder().getCardType()));
        appntObject.setAppNumber(request.getPolicyHolder().getCardNo());
        appntObject.setIsTaxInvoice("0");
        jsonObject.put("appntObject",appntObject);

        //添加 被保人
        List<InsuredObject> insuredObjectList =new ArrayList<>();

        for (int i = 0; i < request.getInsureds().size(); i++) {
            InsuredObject insuredObject =new InsuredObject();
            insuredObject.setInsuredName(request.getInsureds().get(i).getCName());
            insuredObject.setInsuredType("1");
            insuredObject.setInsuredIDType(getAppIdType(request.getInsureds().get(i).getCardType()));
            insuredObject.setInsuredNumber(request.getInsureds().get(i).getCardNo());
            insuredObject.setInsuredTelNumber(request.getInsureds().get(i).getMobile());
            insuredObject.setIsLegal("1");
            insuredObjectList.add(insuredObject);
        }
        jsonObject.put("insuredObject",insuredObjectList);

        //添加自定义责任信息
        DefinedSafeObj definedSafeObj=new DefinedSafeObj();
        definedSafeObj.setIsDefinedSafe("0");

        jsonObject.put("definedSafeObj",definedSafeObj);

        //添加支付信息
        PayObject payObject=new PayObject();
        payObject.setIsSinglePay("1");
        //暂时写死
        payObject.setPayMode("22");
        payObject.setPayDate(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        payObject.setPayBankNo(request.getOrder().getSerialNumber());
        jsonObject.put("payObject",payObject);

        String json=JSONObject.toJSONString(jsonObject);
        MultiValueMap<String,String> map=new LinkedMultiValueMap<>(3);
        map.add("signature",checkSignature(json));
        map.add("json",json);
        map.add("channelCode",channelCode);

        return map;
    }


    /**
     * 请求参数及地址
     * requestUrl
     */
    private static JSONObject responseMessage(MultiValueMap<String,String> map,String url){
        RestTemplate restTemplate =new RestTemplate();
        JSONObject jsonObject;
        List<HttpMessageConverter<?>> httpMessageConverters = restTemplate.getMessageConverters();
        httpMessageConverters.stream().forEach(httpMessageConverter -> {
            if(httpMessageConverter instanceof StringHttpMessageConverter){
                StringHttpMessageConverter messageConverter = (StringHttpMessageConverter) httpMessageConverter;
                messageConverter.setDefaultCharset(CharsetUtil.CHARSET_UTF_8);
            }
        });
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.parseMediaType("application/x-www-form-urlencoded;charset=utf-8"));
        HttpEntity<String> requestParam = new HttpEntity(map, headers);
        ResponseEntity<String> entity = restTemplate.postForEntity(url, requestParam, String.class);
        jsonObject=JSONObject.parseObject(entity.getBody());
        return jsonObject;
    }


    private static  String getAppIdType(String appIdType){

        switch (appIdType){
            case "1":
                return "01";
            case "4":
                return "02";
            case "3":
                return "03";
            case "5":
                return "04";
            case "6":
                return "05";
            case "72":
                return "06";
            case "9":
                return "07";
            case "10":
                return "08";
            case "70":
                return "96";
            case "99":
                return "97";
            default:
        }
        return null;

    }



}
